package com.ray.flow;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jfinal.plugin.activerecord.Db;
import com.ray.model.*;
import com.ray.util.Ret;
import com.ray.util.SerialNumberUtil;
import com.ray.websocket.SysmsgWebsocket;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;

/**
 * 审批流程工具类
 */
@Component
public class FlowService {

    @Value("${spring.datasource.base.name}")
    private String base;

    /**
     * 发起审批工具类
     *
     * @param region         域
     * @param flow_design_no 流程设计编号
     * @param userid         用户编号
     * @param flowForm       表单数据
     * @return
     */
    @Transactional
    public Ret approve(String region, String flow_design_no, String userid, JSONArray flowForm) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        //生成30位的随机序列作为流程编号
        String no = SerialNumberUtil.uuid(30);
        FlowDesign design = FlowDesign.dao.findFirst("select * from flow_design where no = ? and region = ?", flow_design_no, region);
        if (design == null) {
            return Ret.fail("msg", "发起审批失败：没有找到对应的审批流程模板");
        }
        User user = User.dao.findFirst("select * from user where userid = ? and region = ? and is_delete = 0", userid, region);
        if (user == null) {
            return Ret.fail("msg", "发起审批失败：没有找到对应的发起人信息");
        }
        Flow flow = new Flow();
        flow.setRegion(region)
                .setNo(no)
                .setFlowDesignNo(design.getNo())
                .setName(design.getName())
                .setDescription(design.getDescription())
                .setForm(flowForm.toString())
                .setCreateUserId(userid)
                .setCreateUserName(user.getUsername())
                .setAvatar(getAvatarByUserid(region, userid));
        flow.save();
        //根据流程设计编号获取流程节点
        List<FlowDesignNode> node = FlowDesignNode.dao.find("select * from flow_design_node where flow_design_no = ?", flow.getFlowDesignNo());
        //生成当前审批流程所有审批节点
        for (FlowDesignNode fd : node) {
            FlowNode fn = new FlowNode();
            fn.setRegion(fd.getRegion())
                    .setFlowDesignNo(fd.getFlowDesignNo())
                    .setFlowNo(no)
                    .setParentNo(fd.getParentNo())
                    .setNo(fd.getNo())
                    .setName(fd.getName())
                    .setType(fd.getType())
                    .setAssignedType(fd.getAssignedType())
                    .setMulti(fd.getMulti())
                    .setMode(fd.getMode())
                    .setUserid(fd.getUserid())
                    .setUsername(fd.getUsername())
                    .setAvatar(getAvatarByUserid(fd.getRegion(), fd.getUserid()))
                    .setFormUser(fd.getFormUser())
                    .setRefuseType(fd.getRefuseType());
            //设置创建者的用户id和用户名
            if (fd.getType().equals("ROOT")) {
                fn.setUserid(flow.getCreateUserId());
                fn.setUsername(flow.getCreateUserName());
                fn.setAvatar(getAvatarByUserid(fd.getRegion(), flow.getCreateUserId()));
                fn.setHandleTime(new Date());
                fn.setStatu(2);
                //设置审批者的用户id和用户名
            } else if (fd.getType().equals("APPROVAL")) {
                //如果审批类型为自身，则设置审批者的用户id和用户名
                if (fd.getAssignedType().equals("SELF")) {
                    fn.setUserid(flow.getCreateUserId());
                    fn.setUsername(flow.getCreateUserName());
                    fn.setAvatar(getAvatarByUserid(fd.getRegion(), flow.getCreateUserId()));
                    //如果审批类型为表单用户，则从表单中获取审批者的用户id和用户名
                } else if (fd.getAssignedType().equals("FORM_USER")) {
                    JSONArray form = JSONArray.parseArray(flow.getForm());
                    for (int i = 0; i < form.size(); i++) {
                        JSONObject obj = form.getJSONObject(i);
                        //如果表单用户和流程节点中的formUser相同，则设置审批者的用户id和用户名
                        if (obj.getString("en").equals(fd.getFormUser())) {
                            fn.setUserid(obj.getJSONObject("value").getString("userid"));
                            fn.setUsername(obj.getJSONObject("value").getString("username"));
                            fn.setAvatar(getAvatarByUserid(fd.getRegion(), obj.getJSONObject("value").getString("userid")));
                            break;
                        }
                    }
                }
            }
            //通过指定的用户集合生成多人审批子数据
            if (fd.getUserid() != null && fd.getUserid().split(",").length > 1) {
                String[] useridArray = fd.getUserid().split(",");
                String[] usernameArray = fd.getUsername().split(",");
                for (int i = 0; i < useridArray.length; i++) {
                    FlowNodeMulti fnm = new FlowNodeMulti();
                    fnm.setRegion(fd.getRegion())
                            .setFlowNo(no)
                            .setFlowNodeNo(fn.getNo())
                            .setType(fd.getType())
                            .setUserid(useridArray[i])
                            .setUsername(usernameArray[i])
                            .setAvatar(getAvatarByUserid(fd.getRegion(), useridArray[i]))
                            .save();
                }
            }
            fn.save();
        }
        //默认通过发起人节点并流转到下一个节点
        FlowNode rootNode = FlowNode.dao.findFirst("select * from flow_node where flow_no = ? and type = ?", no, "ROOT");
        nextNode(flow, rootNode);
        return Ret.ok("msg", "发起审批成功").set("no", no);
    }

    /**
     * 如果审批同意，则递归下一个节点
     *
     * @param flow     审批流程
     * @param thisNode 当前节点
     */
    public void nextNode(Flow flow, FlowNode thisNode) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        List<FlowNode> nodeList = FlowNode.dao.find("select * from flow_node where flow_no = ? and parent_no = ?", flow.getNo(), thisNode.getNo());
        //如果没有子节点，则流程结束
        if (nodeList.isEmpty()) {
            flow.setStatu(2).setComplateTime(new Date()).update();
            complete(flow);
        } else {
            for (FlowNode node : nodeList) {
                //如果节点为审批节点
                if (node.getType().equals("APPROVAL")) {
                    //节点状态设置为处理中
                    node.setStatu(1);
                    //设置节点时间
                    node.setNodeTime(new Date());
                    node.update();
                    //多人处理模式节点设置
                    if (node.getMulti()) {
                        Db.use(base).update("update flow_node_multi set statu = 1 where flow_no = ? and flow_node_no = ?", flow.getNo(), node.getNo());
                    }
                }
                //如果节点为抄送节点
                else if (node.getType().equals("CC")) {
                    //节点状态设置为已处理
                    node.setStatu(2);
                    //设置节点时间和处理时间
                    node.setNodeTime(new Date());
                    node.setHandleTime(new Date());
                    node.update();
                    //多人处理模式节点设置
                    if (node.getMulti()) {
                        Db.use(base).update("update flow_node_multi set statu = 2 where flow_no = ? and flow_node_no = ?", flow.getNo(), node.getNo());
                    }
                }
                //发送消息给节点人员
                JSONObject message = new JSONObject();
                message.put("title", "您有一个新的审批任务！");
                message.put("content", "进入待审批进行查看");
                SysmsgWebsocket.sendMessage(node.getRegion(), message.toJSONString(), node.getUserid());
            }
            //递归调用下一个节点
            if (nodeList.get(0).getType().equals("CC"))
                nextNode(flow, nodeList.get(0));
        }
    }

    /**
     * 如果审批拒绝，则递归上一个节点
     *
     * @param flow     审批流程
     * @param thisNode 当前节点
     */
    public void frontNode(Flow flow, FlowNode thisNode) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        if (thisNode.getRefuseType().equals("TO_BEFORE")) {
            List<FlowNode> nodeList = FlowNode.dao.find("select * from flow_node where flow_no = ? and no = ?", flow.getNo(), thisNode.getParentNo());
            for (FlowNode node : nodeList) {
                if (node.getType().equals("APPROVAL")) {
                    //节点状态设置为处理中
                    node.setStatu(1).update();
                    //发送消息给节点人员
                    //发送消息给节点人员
                    JSONObject message = new JSONObject();
                    message.put("title", "您有一个新的审批任务，请及时处理！");
                    message.put("content", "进入待审批进行查看");
                    SysmsgWebsocket.sendMessage(node.getRegion(), message.toJSONString(), node.getUserid());
                }
                //如果节点为抄送节点
                else if (node.getType().equals("CC")) {
                    node.setStatu(0).update();
                } else if (node.getType().equals("ROOT")) {
                    flow.setStatu(3).setComplateTime(new Date()).update();
                    complete(flow);
                }
            }
            thisNode.setStatu(4).update();
            //递归调用上一个节点
            if (nodeList.get(0).getType().equals("CC"))
                frontNode(flow, nodeList.get(0));
        } else if (thisNode.getRefuseType().equals("TO_END")) {
            flow.setStatu(3).setComplateTime(new Date()).update();
            complete(flow);
        }
    }

    public void complete(Flow flow) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        FlowDesign fd = FlowDesign.dao.findFirst("select * from flow_design where no = ?", flow.getFlowDesignNo());
        FlowCallback cb = (FlowCallback) Class.forName(fd.getCallback()).newInstance();
        cb.call(flow);
    }

    public String getAvatarByUserid(String region, String userid) {
        String avatar = Db.use(base).queryStr("select avatar from user where userid = ? and region = ?", userid, region);
        return avatar;
    }
}
